
#include "display.h"

#define	SEGMENT_MASK		(SEGMENT_A|SEGMENT_B|SEGMENT_C|SEGMENT_D|SEGMENT_E|SEGMENT_F|SEGMENT_G|SEGMENT_H)

static uint32_t flash_address_cfg __attribute__((at(0xF000))) = 88;

LED_TypeDef LedWork = {LED_WORK_PORT,LED_WORK_PIN};
LED_TypeDef LedError = {LED_ERROR_PORT,LED_ERROR_PIN};
LED_TypeDef LedTx	= {LED_TX_PORT,LED_TX_PIN};
LED_TypeDef LedRx = {LED_RX_PORT,LED_RX_PIN};

CFG_TypeDef CfgBaudrate = {CFG_BAUDRATE_PORT,CFG_BAUDRATE_PIN};
CFG_TypeDef CfgMode = {CFG_MODE_PORT,CFG_MODE_PIN};

typedef enum {
    Digit_0 = SEGMENT_A|SEGMENT_B|SEGMENT_C|SEGMENT_D|SEGMENT_E|SEGMENT_F,
    Digit_1 = SEGMENT_B|SEGMENT_C,
    Digit_2 = SEGMENT_A|SEGMENT_B|SEGMENT_G|SEGMENT_E|SEGMENT_D,
    Digit_3 = SEGMENT_A|SEGMENT_B|SEGMENT_G|SEGMENT_C|SEGMENT_D,
    Digit_4 = SEGMENT_F|SEGMENT_G|SEGMENT_B|SEGMENT_C,
    Digit_5 = SEGMENT_A|SEGMENT_F|SEGMENT_G|SEGMENT_C|SEGMENT_D,
    Digit_6 = SEGMENT_A|SEGMENT_F|SEGMENT_E|SEGMENT_D|SEGMENT_C|SEGMENT_G,
    Digit_7 = SEGMENT_A|SEGMENT_B|SEGMENT_C,
    Digit_8 = SEGMENT_A|SEGMENT_B|SEGMENT_C|SEGMENT_D|SEGMENT_E|SEGMENT_F|SEGMENT_G,
    Digit_9 = SEGMENT_A|SEGMENT_B|SEGMENT_C|SEGMENT_D|SEGMENT_F|SEGMENT_G,
} Segment_Digit_Value_Type;

typedef enum {
    High = SEGMENT_CS2,
    Low	= SEGMENT_CS1,
} Segment_Position_Type;

STATIC INLINE void segment_on (Segment_Position_Type pos)
{
    Chip_GPIO_SetPortMask(LPC_GPIO,SEGMENT_PORT,~(SEGMENT_CS1|SEGMENT_CS2));
    Chip_GPIO_SetMaskedPortValue(LPC_GPIO,SEGMENT_PORT,pos);
}

/*
INLINE void segment_off (void) {
	Chip_GPIO_SetPortMask(LPC_GPIO,SEGMENT_PORT,~(SEGMENT_CS1|SEGMENT_CS2));
	Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,SEGMENT_CS1|SEGMENT_CS2);
}
*/

#ifndef	Delay_ms
#define	Delay_ms(x)	do {				\
		for(int i=0;i<x;i++){ 			\
			for(int j=0;j<64000;j++); \
		}														\
}while(0)
#endif

STATIC INLINE void segment_clear (void)
{
    Chip_GPIO_SetPortMask(LPC_GPIO,SEGMENT_PORT,~SEGMENT_MASK);
    Chip_GPIO_SetPortOutHigh(LPC_GPIO,SEGMENT_PORT,SEGMENT_MASK);
}

STATIC INLINE void segment_value (Segment_Position_Type pos, uint8_t value)
{
    segment_on(pos);
    segment_clear();
    switch(value) {
    case 0:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_0);
        break;
    case 1:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_1);
        break;
    case 2:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_2);
        break;
    case 3:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_3);
        break;
    case 4:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_4);
        break;
    case 5:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_5);
        break;
    case 6:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_6);
        break;
    case 7:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_7);
        break;
    case 8:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_8);
        break;
    case 9:
        Chip_GPIO_SetPortOutLow(LPC_GPIO,SEGMENT_PORT,Digit_9);
        break;
    default:
        break;
    }
}

STATIC INLINE void segment_init(void)
{
    Chip_GPIO_SetPortDIROutput(LPC_GPIO,SEGMENT_PORT,SEGMENT_MASK|SEGMENT_CS1|SEGMENT_CS2);
    segment_clear();
}

void Display_Address(uint8_t value)
{

    int high = value/10;
    int low = value%10;

    segment_value(High, high);
//    for(int i=0; i<0x1FFFF; i++);
    Delay_ms(SEGMENT_DISPLAY_TIME_MS);
    segment_value(Low, low);
//    for(int i=0; i<0x1FFFF; i++);
    Delay_ms(SEGMENT_DISPLAY_TIME_MS);
}

STATIC INLINE void led_init(void)
{
    Chip_GPIO_SetPinDIROutput(LPC_GPIO,LED_WORK_PORT,LED_WORK_PIN);
    Chip_GPIO_SetPinDIROutput(LPC_GPIO,LED_ERROR_PORT,LED_ERROR_PIN);
    Chip_GPIO_SetPinDIROutput(LPC_GPIO,LED_TX_PORT,LED_TX_PIN);
    Chip_GPIO_SetPinDIROutput(LPC_GPIO,LED_RX_PORT,LED_RX_PIN);

    LED_Off(LedWork);
    LED_Off(LedError);
    LED_Off(LedTx);
    LED_Off(LedRx);
}

STATIC INLINE void address_init(void)
{
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,ADDRESS_0_PORT,ADDRESS_0_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,ADDRESS_1_PORT,ADDRESS_1_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,ADDRESS_2_PORT,ADDRESS_2_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,ADDRESS_3_PORT,ADDRESS_3_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,ADDRESS_4_PORT,ADDRESS_4_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,ADDRESS_5_PORT,ADDRESS_5_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,CFG_BAUDRATE_PORT,CFG_BAUDRATE_PIN);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO,CFG_MODE_PORT,CFG_MODE_PIN);
}

void Display_Init(void)
{
    if(!Chip_Clock_IsPeripheralClockEnabled(SYSCTL_CLOCK_GPIO)) {
        Chip_GPIO_Init(LPC_GPIO);
    }
    segment_init();
    led_init();
    address_init();
}

uint32_t Get_Address(void)
{
    uint32_t add = 0;
    Chip_GPIO_SetPortMask(LPC_GPIO,0,0);
    Chip_GPIO_SetPortMask(LPC_GPIO,1,0);
    Chip_GPIO_SetPortMask(LPC_GPIO,4,0);

    if(Chip_GPIO_GetPinState(LPC_GPIO,CFG_MODE_PORT,CFG_MODE_PIN)) {

        if(Chip_GPIO_GetPinState(LPC_GPIO,ADDRESS_0_PORT,ADDRESS_0_PIN))
            add |= 1;
        if(Chip_GPIO_GetPinState(LPC_GPIO,ADDRESS_1_PORT,ADDRESS_1_PIN))
            add |= (1<<1);
        if(Chip_GPIO_GetPinState(LPC_GPIO,ADDRESS_2_PORT,ADDRESS_2_PIN))
            add |= (1<<2);
        if(Chip_GPIO_GetPinState(LPC_GPIO,ADDRESS_3_PORT,ADDRESS_3_PIN))
            add |= (1<<3);
        if(Chip_GPIO_GetPinState(LPC_GPIO,ADDRESS_4_PORT,ADDRESS_4_PIN))
            add |= (1<<4);
        if(Chip_GPIO_GetPinState(LPC_GPIO,ADDRESS_5_PORT,ADDRESS_5_PIN))
            add |= (1<<5);
    } else {
        add = flash_address_cfg;
    }
    return add;
}

void LED_On(LED_TypeDef led)
{
    Chip_GPIO_SetPortMask(LPC_GPIO,led.port,0);
    Chip_GPIO_SetPinOutLow(LPC_GPIO,led.port,led.pin);
}

void LED_Off(LED_TypeDef led)
{
    Chip_GPIO_SetPortMask(LPC_GPIO,led.port,0);
    Chip_GPIO_SetPinOutHigh(LPC_GPIO,led.port,led.pin);
}

void LED_Toggle(LED_TypeDef led)
{
    Chip_GPIO_SetPortMask(LPC_GPIO,led.port,0);
    Chip_GPIO_SetPinToggle(LPC_GPIO,led.port,led.pin);
}

bool Get_Cfg_Pin_Value(CFG_TypeDef cfg)
{
    Chip_GPIO_SetPortMask(LPC_GPIO,cfg.port,0);
    return Chip_GPIO_GetPinState(LPC_GPIO,cfg.port,cfg.pin);
}
